package edu.csl.study.springboot.common;

import edu.csl.study.springboot.common.exception.BusinessException;
import edu.csl.study.springboot.common.exception.ErrorDefine;
import edu.csl.study.springboot.common.exception.TipTools;
import lombok.extern.log4j.Log4j2;
import org.apache.catalina.connector.ClientAbortException;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

@ControllerAdvice
@Log4j2
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ModelAndView exceptionHandler(Exception exception, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws Exception {
        //获取拦截器判断的返回结果类型
        Object o = httpRequest.getAttribute(SysConsts.IS_METHOD_RETURN_VIEW);
        if (o == null) {
            log.error("", exception);
            throw exception;
        }
        //是否是html/text
        boolean isView = (Boolean) o;

        ApiResponse response = new ApiResponse();
        StringBuffer msg =new StringBuffer();
        response.setCode(ErrorDefine.UNKNOWN_ERROR.code);
        if(exception instanceof MethodArgumentNotValidException){
            MethodArgumentNotValidException validException = (MethodArgumentNotValidException)exception;
            BindingResult result=validException.getBindingResult();
            List<ObjectError> errors=result.getAllErrors();
            for(ObjectError error:errors){
                msg.append(error.getObjectName());
                msg.append(":\t");
                msg.append(error.getDefaultMessage());
                msg.append("\n");
            }
            response.setMessage(msg.toString());
            log.error(msg.toString(),exception);
        }else if(exception instanceof ConstraintViolationException){
            ConstraintViolationException validatorExceptions = (ConstraintViolationException) exception;
            Set<ConstraintViolation<?>> contraints=validatorExceptions.getConstraintViolations();
            for(ConstraintViolation<?> contraint:contraints){
                msg.append(contraint.getMessageTemplate());
                msg.append("\n");
            }
            log.info("【业务异常】-"+msg.toString());
        }else if(exception instanceof BusinessException || exception.getCause() instanceof BusinessException){//2017-06-21 新增对系统业务异常的处理(去掉BusinessException:开头)
            BusinessException businessException = (BusinessException)(exception.getCause());
            if(businessException != null){
                msg.append(businessException.getMessage());
            }else{
                msg.append(exception.getMessage());
            }
            response.setCode(businessException.getErrorCode());
            log.info("【业务异常】-"+msg.toString());
        }else if(exception instanceof ClientAbortException){
            msg.append("系统异常："+ ExceptionUtils.getRootCauseMessage(exception));
            if(exception.getMessage() != null && exception.getMessage().indexOf("断开的管道") >-1){
                log.error("【系统异常】-"+exception.getMessage());
            }else{
                log.error("【系统异常】-"+exception.getMessage(),exception);
            }
        }else{
            log.error("【系统异常】-"+exception.getMessage(),exception);
            String tipMessage = TipTools.unknowExceptionTipMsg("系统",exception,40);
            msg.append(tipMessage);

        }
        response.setMessage(msg.toString());
        if(isView){
            ModelAndView modelAndView = new ModelAndView("/error");//配置需要跳转的Controller方法
            httpRequest.setAttribute("message", response.getMessage());
            return modelAndView;
        }else{
            ModelAndView  modelAndView = new ModelAndView(new MappingJackson2JsonView());
            modelAndView.addObject("code", response.getCode());
            modelAndView.addObject("message", response.getMessage());
            modelAndView.addObject("data", null);
            return modelAndView;
        }
    }
}
